home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 May: Tool Chest / Dev.CD May 98 TC.toast / Tool Chest / Development Kits / HyperCard Related / APDA HyperCard Toolkits / HyperCard CTB Toolkit 1.0b2 / Source Code / CTBEditUpTo.p < prev    next >
Encoding:
Text File  |  1995-02-07  |  9.7 KB  |  359 lines  |  [TEXT/MPS ]

  1. (*
  2.     CTBEditUpTo([termChar[,timeOut[,wrapCol[,limit]]]]) -- Receive characters until the termChar is
  3.         received, or until timeOut 60ths of a second have passed. Echo incoming characters to the
  4.         output, and allow editing. Wrap the input at wrapCol columns by inserting returns.
  5.  
  6.     Note: This XCMD assumes relatively small amounts of low bandwidth data. So it isn't real careful
  7.     about time efficiency. It's primarily intended to allow the Mac to play the host side of a dial-in
  8.     connection.
  9.  
  10.     To compile and link this file using Macintosh Programmer's Workshop,
  11.  
  12.         pascal -w CTBEditUpTo.p
  13.         link -m ENTRYPOINT -o HyperCommands -rt XFCN=2763 -sn Main=CTBEditUpTo ∂
  14.             CTBEditUpTo.p.o "{MPW}"Libraries:interface.o "{MPW}"Libraries:Libraries:HyperXLib.o
  15.  
  16.     © Copyright 1990 by Apple Computer, Inc.
  17.  
  18.     Initial coding 2/90 by Harry R. Chesley.
  19. *)
  20.  
  21. {$R-}
  22.  
  23. {$S CTBEditUpTo }     { Segment name must be the same as the command name. }
  24.  
  25. unit DummyUnit;
  26.  
  27. interface
  28.  
  29. uses MemTypes, QuickDraw, OSIntf, ToolIntf, CTBUtils, FTIntf, CMIntf, TMIntf, CRMIntf, HyperXCmd;
  30.  
  31. procedure EntryPoint(paramPtr: XCmdPtr);
  32.     
  33. implementation
  34.  
  35. procedure CTBEditUpTo(paramPtr: XCmdPtr); forward;
  36.  
  37. procedure EntryPoint(paramPtr: XCmdPtr);
  38.  
  39.     begin
  40.         CTBEditUpTo(paramPtr);
  41.     end;
  42.  
  43. procedure CTBEditUpTo(paramPtr: XCmdPtr);
  44.  
  45.     {$I CTBUtil.inc}
  46.  
  47.     const return = 13;        { Carriage return. }
  48.         linefeed = 10;            { Line feed. }
  49.         backspace = 8;            { Back space. }
  50.         delete = 127;            { Delete. }
  51.         space = ord(' ');        { Space. }
  52.         tab = 9;                    { Horizontal tab. }
  53.  
  54.     var lookForTerm: boolean;
  55.         termString: Ptr;
  56.         termPtr, oldTermPtr: Ptr;
  57.         stopAt: longInt;
  58.         timeOut: longInt;
  59.         wrapCol: longInt;
  60.         col: longInt;
  61.         gotIt: boolean;
  62.         toRead: longInt;
  63.         toCopy: longInt;
  64.         oldSize: longInt;
  65.         l, l2: longInt;
  66.         h: Handle;
  67.         p: Ptr;
  68.         sizes: CMBufferSizes;
  69.         status: CMStatFlags;
  70.         theBuf: InputBufferHandle;
  71.         b: SignedByte;
  72.         plusCount: integer;
  73.         recvMax: longInt;
  74.  
  75.     procedure Fail(errMsg: Str255); { set theResult and quit }
  76.         begin
  77.             { If we had the termination string parameter locked down, unlock it. }
  78.             if lookForTerm then HUnlock(paramPtr^.params[1]);
  79.             paramPtr^.returnValue := PasToZero(paramPtr,errMsg);
  80.             exit(CTBEditUpTo);
  81.         end;
  82.  
  83.     procedure putByte(theByte: SignedByte);
  84.         { Add a byte to the handle h. }
  85.  
  86.         var sz: longInt;
  87.             p: Ptr;
  88.  
  89.         begin
  90.             sz := GetHandleSize(h);
  91.             SetHandleSize(h,sz+1);
  92.             if MemError <> noErr then
  93.                 begin
  94.                     DisposHandle(h);
  95.                     Fail('Out of memory');
  96.                 end;
  97.             p := Ptr(ord4(h^)+sz);
  98.             p^ := theByte;
  99.             recvMax := recvMax+1;
  100.         end;
  101.  
  102.     function backspaceByte: SignedByte;
  103.         { Backspace out a byte from the handle. }
  104.  
  105.         var sz: longInt;
  106.             p: Ptr;
  107.  
  108.         begin
  109.             sz := GetHandleSize(h);
  110.             if sz > 0 then
  111.                 begin
  112.                     p := Ptr(ord4(h^)+sz-1);
  113.                     backspaceByte := p^;
  114.                     SetHandleSize(h,sz-1);
  115.                     recvMax := recvMax-1;
  116.                 end
  117.             else backspaceByte := 0;
  118.         end;
  119.  
  120.     procedure sendByte(theByte: SignedByte);
  121.         { Send a byte to the connection, making sure we don't accidentally trip up a modem with "+++". }
  122.  
  123.         const plus = ord('+');
  124.  
  125.         var ioSize: longInt;
  126.             b: array [1..1] of SignedByte;
  127.             flags: integer;
  128.             err: OSErr;
  129.  
  130.         begin
  131.             { If we were supposed to send a plus previously, send it now with the next character. }
  132.             if plusCount = 3 then
  133.                 begin
  134.                     ioSize := 1;
  135.                     b[1] := plus;
  136.                     flags := cmFlagsEOM;
  137.                     err := CMWrite(Globals^^.connHand,@b,ioSize,cmData,false,nil,-1,flags);
  138.                     plusCount := 0;
  139.                 end
  140.             { Otherwise, if we are now about to send a plus, increment the counts of pluses sent. }
  141.             else if theByte = plus then plusCount := plusCount+1
  142.             { Otherwise we're not sending a plus, so clear the plus count. }
  143.             else plusCount := 0;
  144.             { If we're not about to send the third plus (which might be a modem attention), then send it normally. }
  145.             if plusCount <> 3 then
  146.                 begin
  147.                     ioSize := 1;
  148.                     b[1] := theByte;
  149.                     flags := cmFlagsEOM;
  150.                     err := CMWrite(Globals^^.connHand,@b,ioSize,cmData,false,nil,-1,flags);
  151.                     { If that was a return, add on a linefeed. }
  152.                     if theByte = return then sendByte(linefeed);
  153.                 end;
  154.         end;
  155.  
  156.     procedure sendBS;
  157.         { Send a sequence to erase the previous character. }
  158.  
  159.         begin
  160.             sendByte(backspace); sendByte(space); sendByte(backspace);
  161.         end;
  162.  
  163.     begin
  164.         { Assume not termination string, and check the parameter count. }
  165.         lookForTerm := false;
  166.         if paramPtr^.paramCount > 4 then Fail('Invalid parameter count');
  167.  
  168.         { Make sure the Comm Toolbox is ready and able. }
  169.         CTBReady;
  170.         { And that the connection tool is there. }
  171.         EnsurePresent(connectionTool);
  172.         { And open. }
  173.         EnsureOpen;
  174.  
  175.         { Get the buffer. }
  176.         theBuf := InputBufferHandle(CMGetUserData(Globals^^.connHand));
  177.         { If there's a termination string already set, get rid of it. }
  178.         if theBuf^^.termString <> nil then
  179.             begin
  180.                 DisposHandle(theBuf^^.termString);
  181.                 theBuf^^.termString := nil;
  182.                 theBuf^^.timeOut := -1;
  183.             end;
  184.  
  185.         { Get the termination string (if there is one). }
  186.         if ParmPresent(1) then
  187.             begin
  188.                 lookForTerm := true;
  189.                 HLock(paramPtr^.params[1]);
  190.                 termString := paramPtr^.params[1]^;
  191.                 termPtr := termString;
  192.             end;
  193.         { Get the time-out. }
  194.         if ParmPresent(2) then timeOut := GetLongParm(2)
  195.         else timeOut := 0;
  196.         stopAt := TickCount + timeOut;
  197.         { Get the column to wrap at. }
  198.         if ParmPresent(3) then wrapCol := GetLongParm(3)
  199.         else wrapCol := 72;
  200.         { Get the character limit. }
  201.         if ParmPresent(4) then theBuf^^.recvLimit := GetLongParm(4)
  202.         else theBuf^^.recvLimit := 50000;
  203.  
  204.         { Create the answer handle. }
  205.         h := NewHandle(0);
  206.         if h = nil then Fail('Out of memory');
  207.  
  208.         { Loop until we've got an acceptible result. }
  209.         gotIt := false;
  210.         col := 1;
  211.         plusCount := 0;
  212.         repeat
  213.             { If there's nothing left in the buffer, try to fill it. }
  214.             if theBuf^^.amountLeft = 0 then
  215.                 begin
  216.                     { Figure out how much data's available to read. }
  217.                     if CMStatus(Globals^^.connHand,sizes,status) = noErr then
  218.                         begin
  219.                             if BAnd(status,cmStatusOpening+cmStatusListenPend+cmStatusIncomingCallPresent+
  220.                                             cmStatusOpen) = 0 then leave;
  221.                             toRead := min(sizes[cmDataIn],BUFFERSIZE)
  222.                         end
  223.                     else toRead := 0;
  224.                     { Read it in. }
  225.                     if toRead > 0 then toRead := ReadFromConn(@theBuf^^.buffer,toRead);
  226.                     theBuf^^.bufferPtr := @theBuf^^.buffer;
  227.                     theBuf^^.amountLeft := toRead;
  228.                 end;
  229.             { Check if there's anything to do, and whether there's any time left. }
  230.             if (theBuf^^.amountLeft <= 0) and ((TickCount - stopAt) > 0) then leave;
  231.             if theBuf^^.amountLeft > 0 then stopAt := TickCount + timeOut;
  232.             { Loop through the new input. }
  233.             gotIt := false;
  234.             while (not gotIt) and (theBuf^^.amountLeft > 0) and (recvMax > 0) do
  235.                 begin
  236.                     { Get the next byte. }
  237.                     with theBuf^^ do
  238.                         begin
  239.                             b := BAnd(bufferPtr^,$7F);
  240.                             bufferPtr := Ptr(ord4(bufferPtr)+1);
  241.                             amountLeft := amountLeft-1;
  242.                         end;
  243.  
  244.                     { Should we auto-wrap? }
  245.                     if (col > wrapCol) and (b <> return) then
  246.                         begin
  247.                             { If this is a space, then auto-wrapping is easy. }
  248.                             if b = space then b := return
  249.                             else
  250.                                 begin
  251.                                     { Otherwise, we need to back out to the previous space and put that on the next line. }
  252.                                     l := GetHandleSize(h);
  253.                                     p := Ptr(ord4(h^)+l-1);
  254.                                     l := 1;
  255.                                     while p <> h^ do
  256.                                         begin
  257.                                             if (p^ = space) or (p^ = return) then leave;
  258.                                             p := Ptr(ord4(p)-1);
  259.                                             l := l+1;
  260.                                         end;
  261.                                     if l >= wrapCol then
  262.                                         begin
  263.                                             sendByte(return);
  264.                                             putByte(return);
  265.                                             col := 1;
  266.                                         end
  267.                                     else
  268.                                         begin
  269.                                             HLock(h);
  270.                                             p^ := return;
  271.                                             for l2 := 1 to l do sendBS;
  272.                                             for l2 := 1 to l do
  273.                                                 begin
  274.                                                     sendByte(p^);
  275.                                                     p := Ptr(ord4(p)+1);
  276.                                                 end;
  277.                                             HUnlock(h);
  278.                                             col := l;
  279.                                         end;
  280.                                 end;
  281.                         end;
  282.  
  283.                     { Control character? }
  284.                     if ((b >= 0) and (b < space) and (b <> return) and (b <> tab)) or (b = delete) then
  285.                         begin
  286.                             { Backspace or delete? }
  287.                             if (b = backspace) or (b = delete) then
  288.                                 begin
  289.                                     { Do the backspace. }
  290.                                     if col > 1 then
  291.                                         begin
  292.                                             sendBS;
  293.                                             b := backspaceByte;
  294.                                             col := col-1;
  295.                                             if termPtr <> termString then termPtr := Ptr(ord4(termPtr)-1);
  296.                                         end;
  297.                                 end;
  298.                         end
  299.                     else
  300.                         begin
  301.                             { Send and record the byte. }
  302.                             sendByte(b);
  303.                             putByte(b);
  304.                             if b = return then col := 1
  305.                             else col := col+1;
  306.  
  307.                             { Check for termination string. }
  308.                             if lookForTerm then
  309.                                 begin
  310.                                     { Did this one match the next byte in the termination? }
  311.                                     if b = termPtr^ then
  312.                                         begin
  313.                                             termPtr := Ptr(ord4(termPtr)+1);
  314.                                             if termPtr^ = 0 then
  315.                                                 begin
  316.                                                     gotIt := true;
  317.                                                     leave;
  318.                                                 end;
  319.                                         end
  320.                                     else
  321.                                         begin
  322.                                             { If not, then recalculate where we are in the termination string. }
  323.                                             l := ord4(termPtr)-ord4(termString)-1;
  324.                                             oldTermPtr := termPtr;
  325.                                             termPtr := termString;
  326.                                             while l > 0 do
  327.                                                 begin
  328.                                                     p := Ptr(ord4(oldTermPtr)-l);
  329.                                                     l2 := l;
  330.                                                     while l2 > 0 do
  331.                                                         begin
  332.                                                             if p^ <> termPtr^ then leave;
  333.                                                             p := Ptr(ord4(p)+1);
  334.                                                             termPtr := Ptr(ord4(termPtr)+1);
  335.                                                             l2 := l2-1;
  336.                                                         end;
  337.                                                     if (l2 = 0) and (b = termPtr^) then leave;
  338.                                                     l := l-1;
  339.                                                     termPtr := termString;
  340.                                                 end;
  341.                                             if b = termPtr^ then termPtr := Ptr(ord4(termPtr)+1)
  342.                                             else termPtr := termString;
  343.                                         end;
  344.                                 end;
  345.                         end;
  346.                 end
  347.         until gotIt;
  348.  
  349.         { Unlock the termination string parameter. }
  350.         if lookForTerm then HUnlock(paramPtr^.params[1]);
  351.  
  352.         { Terminate and strip the handle and return it. }
  353.         StripBytes(h,GetHandleSize(h),true);
  354.  
  355.         paramPtr^.returnValue := h;
  356.     end;
  357.  
  358. end.
  359.